package de.fsujena.chat_pi.client;

import java.io.Console;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Date;

import de.fsujena.chat_pi.client.userInterface.GraphicalUI;
import de.fsujena.chat_pi.connection.Connector;
import de.fsujena.chat_pi.connection.RSAException;
import de.fsujena.chat_pi.ressources.Room;
import de.fsujena.chat_pi.ressources.User;
import de.fsujena.chat_pi.ressources.message.Message;
import de.fsujena.chat_pi.ressources.message.SysMessage;
import de.fsujena.chat_pi.ressources.message.TextMessage;




public class ConnectionThread extends Thread {
	public InputStream in = null;
	public OutputStream out = null;
	public boolean greeting=false;
	public boolean reading=false;
	public boolean loggedIn=false;
	public String username;
	public String newusername;
	public String newpassword;
	public String password;
	public Client mainThread;
	public MessageHandler messageHandler;
	User nullUser=null;
	public Room foyer=new Room("Foyer",null,0,nullUser);
	Client clientObject;
	//BufferedReader input = new BufferedReader(new InputStreamReader(System.in));	

	Socket server;
	Connector connector;
	// Console console = System.console();
	Console console = null;								//reference to the system console(not really needed)

	

	/**
	 * creates new Thread and connects to the server
	 * @param ip	ip of the server
	 * @param port	port on which the server runs
	 * @throws IOException if there is an error setting up the new connection to the server
	 * @throws RSAException if there is an error setting up the RSA encryption
	 */
	public ConnectionThread(String ip, int port, Client clientObject) throws IOException, RSAException {
		server = new Socket(ip, port);
		connector=new Connector(server,true,true);			
		connector.init();
		this.clientObject=clientObject;
	}

	/* (non-Javadoc)
	 * @see java.lang.Thread#run()
	 */
	/* (non-Javadoc)
	 * @see java.lang.Thread#run()
	 */
	/**
	 * Receives the messages and processes them
	 */
	public void run() {
		
		
		messageHandler=new MessageHandler(mainThread);
		reading=true;										//Enables the loop
		while (reading) {									//the loop
			
			Object inputObject;
				try {
					inputObject = null;
					inputObject = connector.readGeneralObject();	//reading the Object from the server		
					if(inputObject instanceof Message){
					if(!messageHandler.handle((Message)inputObject)){
						mainThread.UI.postError("unable to process message");
					}
					}else {
						mainThread.UI.postError("wrong inputobject");
					}
							} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {							//catch exception on error (e.g.if connection to server is interrupted)
					//e.printStackTrace();
					if(reading){									//only true if connection lost unexpected
					reading=false;									//stops loop
					clientObject.UI.postError("lost connection to server");//print error to the user
					try {
						server.close();								//close the socket
						server=null;								//free resources
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					this.disconnect();								//stop thread
					}
				}
							
		}

	}

	/**
	 * send a message object to the server
	 * @param msg message object to send
	 */
	public void sendMessage(Message msg) {
		try {
			connector.sendMessageObject(msg);				//sends message
		} catch (IOException e) {
			//e.printStackTrace();
			clientObject.UI.postError("Error sending message.");	//print error 
		}		
		return;
	}

	/**
	 * stops the thread and free recources
	 */
	public void disconnect() {
		reading=false;								//stops the reading loop
		try {
			if(server!=null)this.server.close();	//check if server isn't already closed and close it if not
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			this.finalize();						//call garbage collector
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return;
	}

	
	/**
	 * sends system message to the server
	 * @param cat	category of the message
	 * @param msg	messagecode
	 */
	public void sendSysMessage(SysMessage.CATEGORY cat, SysMessage.MESSAGE msg) {
		SysMessage sysMsg = new SysMessage(cat, msg);		//create message object
		sysMsg.setSent(new Date());							//write date
		sysMsg.setSenderUsername(username);					//set username
		try {
			connector.sendMessageObject(sysMsg);			//send message
		} catch (IOException e) {
			e.printStackTrace();
			clientObject.UI.postError("Error sending message.");	//print error otherwise
		}
	}
	
	/**
	 * sends system message to the server
	 * @param cat	category of the message
	 * @param msg	messagecode
	 * @param msgStr string message of the systemmessage
	 */
	public void sendSysMessage(SysMessage.CATEGORY cat, SysMessage.MESSAGE msg, String msgStr) {
		SysMessage sysMsg = new SysMessage(cat, msg, msgStr);	//create message object
		sysMsg.setSent(new Date());								//write date
		sysMsg.setSenderUsername(username);						//set username
		try {
			connector.sendMessageObject(sysMsg);				//send message
		} catch (IOException e) {
			e.printStackTrace();
			clientObject.UI.postError("Error sending message.");		//print error otherwise
		}
	}
	
	/**
	 * sends system message to the server
	 * @param cat	category of the message
	 * @param msg	messagecode
	 * @param msgStr string message of the systemmessage
	 * @param msgObj object that will be sent 
	 */
	public void sendSysMessage(SysMessage.CATEGORY cat, SysMessage.MESSAGE msg, String msgStr, Object msgObj) {
		SysMessage sysMsg = new SysMessage(cat, msg, msgStr);	//create message object
		sysMsg.setMessageObject(msgObj);						//sets the object to send
		sysMsg.setSent(new Date());								//write date
		sysMsg.setSenderUsername(username);						//set username
		try {
			connector.sendMessageObject(sysMsg);				//send message
		} catch (IOException e) {
			e.printStackTrace();
			clientObject.UI.postError("Error sending message.");		//print error otherwise
		}
	}
	
	
		
	
	/**
	 * send a TextMessage to the server
	 * @param msg string containing the message
	 */
	public void sendTextMessage(String msg) {

		TextMessage textMsg = new TextMessage(msg);			//creates new TextMessage object
		textMsg.setSent(new Date());						//writes the actual date to the message
		textMsg.setSenderUsername(username);				//writes the username to the message
		if (loggedIn){
		//mainThread.msgArray.add(textMsg);					//saves msg to history
		//mainThread.worker.saveHistory();
		}
		sendMessage(textMsg);								//send it via the connectionthread
		return;
	}
}
		
